@using System.Net
@using Duende.Bff.Blazor.Client
@using Microsoft.Extensions.Options
@inject IRenderModeContext RenderModeContext
@inject IHttpClientFactory Factory
@inject IOptions<BffBlazorClientOptions> Options
@inject NavigationManager Navigation
@inject AuthenticationStateProvider GetAuthenticationStateAsync

<div class="card">
    <h3 class="card-header">@Header</h3>
    <div class="card-body">
        <AuthorizeView>
            <NotAuthorized>
                <p>You are not logged in.</p>
            </NotAuthorized>
            <Authorized>
                <h5 class="card-subtitle">@RenderModeContext.WhereAmI()</h5>

                @if(_apiResult != null)
                {
                    <p class="card-text">
                        Token ID: @_apiResult.Jti
                        <br />Retrieved at @_apiResult.Time
                    </p>
                } else
                {
                    <p class="card-text">API Result: not called yet</p>
                }

                <button class="btn btn-primary" disabled="@DisableUi" @onclick="CallApiAsync">Call API</button>
            </Authorized>
        </AuthorizeView>
    </div>
</div>

@code {
    [Parameter] public string Header { get; set; } = string.Empty;

    [Parameter] public bool DisableUi { get; set; } = true;

    private HttpClient _http = null!;

    private ApiResult? _apiResult;

    protected override void OnInitialized()
    {
        _http = Factory.CreateClient("callApi");
    }

    protected async Task CallApiAsync()
    {
        DisableUi = true;
        try
        {
            _apiResult = await _http.GetFromJsonAsync<ApiResult>("user-token");
        }
        catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.Unauthorized)
        {
            // The user is not authenticated. This can happen if the authentication cookie
            // is valid longer than the refresh token. The server already logs the user
            // out. In theory, we could just 'refresh' the page, but this might cause 
            // an endless auth loop. 
            Navigation.NavigateTo(await BffLogoutUrl(), forceLoad: true);
        }

        DisableUi = false;
    }

    async Task<string> BffLogoutUrl()
    {
        var context = await GetAuthenticationStateAsync.GetAuthenticationStateAsync();
        var logoutUrl =  context.User.FindFirst(Constants.ClaimTypes.LogoutUrl);
        if (logoutUrl == null) throw new InvalidOperationException("The logout url is missing");
        return $"{Options.Value.StateProviderBaseAddress}{logoutUrl.Value}";
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if(firstRender)
        {
            DisableUi = false;
            StateHasChanged();
        }
    }

    public record ApiResult(string Jti, string Time);
}